﻿using MenuChanger;
using MenuChanger.MenuElements;
using MenuChanger.Extensions;
using ItemSyncMod.MenuExtensions;
using MenuChanger.MenuPanels;
using RandomizerMod.Menu;
using RandomizerMod;
using RandoSettingsManager.Menu;
namespace ItemSyncMod.Menu
{
    public class ItemSyncMenu
    {
        public static ItemSyncMenu instance;
        internal delegate void MenuReverted();
        internal delegate void Connected();
        internal delegate void Disconnected();
        internal delegate void Ready(Dictionary<string, string> metadata);
        internal delegate void Unready();
        internal delegate void RoomStateUpdated(int playersCount, string[] playersNames);
        internal delegate void LockSettings();
        internal delegate void GameStarted();
        internal delegate void GameJoined();

        internal event MenuReverted OnMenuRevert;
        internal event Connected OnConnected;
        internal event Disconnected OnDisconnected;
        internal event Ready OnReady;
        internal event Unready OnUnready;
        internal event RoomStateUpdated OnRoomStateUpdated;
        internal event LockSettings OnLockSettings;
        internal event GameStarted OnGameStarted;
        internal event GameJoined OnGameJoined;

        internal SettingsSharer SettingsSharer;
        internal bool IsReadied => readyButton.Value;

        private MenuPage menuPage;
        //定制 身份选择。
        private BigButton hostButton, searchButton;
        //定制 搜索房间
        private GridItemPanel roomsPanel;
        private MenuLabel searchRoomHint;

        private BigButton openMenuButton, startButton, joinGameButton;
        private DynamicToggleButton connectButton, readyButton;
        private EntryField<string> urlInput;
        private MenuLabel serverNameLabel;
        private LockableEntryField<string> nicknameInput, roomInput;
        private CounterLabel readyPlayersCounter;
        private DynamicLabel readyPlayersBox;
        private Thread connectThread;

        private MenuLabel additionalSettingsLabel, localPHollowKnightRefsLabel;
        private ToggleButton syncVanillaItemsButton, syncSimpleKeysUsagesButton;

        #region Extensions Menu
        private MenuPage extensionsMenuPage;
        private SmallButton openExtensionsMenuButton;
        private MultiGridItemPanel extensionsGrid;
        #endregion

        internal ItemSyncMenu(MenuPage connectionsPage)
        {
            instance = this;
            SettingsSharer = new(this);

            CreateMenuElements(connectionsPage);
            AddEvents();
            Arrange();

            RevertToInitialState();
        }

        internal void Dispose() => ClientConnection.ClearMenuListener(this);

        internal void ShowStartGameFailure()
        {
            connectButton.Show();
            readyPlayersBox.SetText("Failed to start game.\nPlease check ModLog.txt for more info.");
        }

        private void CreateMenuElements(MenuPage finalPage)
        {
            menuPage = new("Continue", finalPage);
            openMenuButton = new(finalPage, Localization.Localize("ItemSync"));

            //定制 身份选择
            hostButton = new(menuPage, LocalizeRando("Host Game"));
            searchButton = new(menuPage, LocalizeRando("Search Room"));

            //定制 搜索房间
            roomsPanel = new(menuPage, new(0, 450), 1, 60, 0, true, new IMenuElement[0]);
            searchRoomHint = new(menuPage,"", MenuLabel.Style.Title);

            urlInput = new(menuPage, "URL: ");
            urlInput.InputField.characterLimit = 120;
            connectButton = new(menuPage, "Connect");
            serverNameLabel = new(menuPage, LocalizeRando("Server Name: "));

            nicknameInput = new(menuPage, LocalizeRando("Nickname: "));
            nicknameInput.InputField.characterLimit = 30;

            roomInput = new(menuPage, LocalizeRando("Room: "));
            roomInput.InputField.characterLimit = 60;
            readyButton = new(menuPage, LocalizeRando("Ready"));
            readyPlayersBox = new(menuPage, "", MenuLabel.Style.Body);
            readyPlayersCounter = new(menuPage, LocalizeRando("Ready Players: "));

            startButton = new(menuPage, LocalizeRando("Start ItemSync"));

            additionalSettingsLabel = new(menuPage, LocalizeRando("Additional Settings"));
            syncVanillaItemsButton = new(menuPage, LocalizeRando("Sync Vanilla Items"));
            syncSimpleKeysUsagesButton = new(menuPage, LocalizeRando("Sync Simple Keys Usages"));

            localPHollowKnightRefsLabel = new(menuPage, LocalizeRando("Local Preferences"));
            
            joinGameButton = new(menuPage, LocalizeRando("Join Game"));
            joinGameButton.AddSetResumeKeyEvent("Randomizer");
            joinGameButton.Hide(); // Always hidden for obvious reasons

            // Extensions Menu
            extensionsMenuPage = new("ItemSyncExtensionsMenu", menuPage);
            openExtensionsMenuButton = new(menuPage, LocalizeRando("Extensions"));
            ExtensionsMenuAPI.ResetMenuEvents();

            extensionsGrid = new(extensionsMenuPage, 8, 3, 60f, 650f, new(0, 300), Array.Empty<SmallButton>());
            ExtensionsMenuAPI.ConstructExtensionsMenus(extensionsMenuPage).ForEach(
                button => extensionsGrid.Add(button));

            // Load last values from settings
            //定制 - 硬编码
            urlInput.SetValue(ItemSyncMod.GS.URL);
            nicknameInput.SetValue(LocalizeRando(ItemSyncMod.GS.UserName));
            syncVanillaItemsButton.SetValue(ItemSyncMod.GS.SyncVanillaItems);
            syncSimpleKeysUsagesButton.SetValue(ItemSyncMod.GS.SyncSimpleKeysUsages);
        }

        internal void ConnectionOnConnect(ulong uid, string serverName) => ConnectAcknowledged(uid, serverName);

        internal void ConnectionOnReadyConfirm(int ready, string[] names) => InvokeOnRoomStateUpdated(ready, names);

        internal void ConnectionOnReadyDeny(string msg) => ThreadSupport.BeginInvoke(() => ShowReadyDeny(msg));

        internal void ConnectionOnGameStarted() => InvokeOnGameStarted();

        private void AddEvents()
        {
            openMenuButton.AddHideAndShowEvent(menuPage);
            connectButton.OnClick += () => ThreadSupport.BeginInvoke(ConnectClicked);

            //定制 - 身份选择
            hostButton.OnClick += () => ThreadSupport.BeginInvoke(HostClicked);
            searchButton.OnClick += () => ThreadSupport.BeginInvoke(SearchClicked);

            nicknameInput.ValueChanged += (value) => ThreadSupport.BeginInvoke(() => UpdateNickname(value));
            nicknameInput.InputField.onValidateInput += (text, index, c) => c == ',' ? '.' : c; // ICU

            readyButton.OnClick += () => ThreadSupport.BeginInvoke(ReadyClicked);
            OnRoomStateUpdated += (num, players) => ThreadSupport.BeginInvoke(() => UpdateReadyPlayersLabel(num, players));
            OnRoomStateUpdated += (_, _) => ThreadSupport.BeginInvoke(EnsureStartButtonShown);

            #region Additional Sync Features
            SettingsSharer.OnValueChanged callback1 = SettingsSharer.RegisterSharedSetting(
                "ItemSync-SyncVanillaItems", GetSyncVanillaItems, SetSyncVanillaItems);
            syncVanillaItemsButton.OnClick += () => callback1();
            syncVanillaItemsButton.ValueChanged += value => 
                ItemSyncMod.GS.SyncVanillaItems = value;

            SettingsSharer.OnValueChanged callback2 = SettingsSharer.RegisterSharedSetting(
                "ItemSync-SyncSimpleKeysUsage", GetSyncSimpleKeysUsages, SetSyncSimpleKeysUsages);
            syncSimpleKeysUsagesButton.OnClick += () => callback2();
            syncSimpleKeysUsagesButton.ValueChanged += value =>
                ItemSyncMod.GS.SyncSimpleKeysUsages = value;

            #endregion

            startButton.OnClick += () => ThreadSupport.BeginInvoke(InitiateGame);
            OnGameStarted += () => ThreadSupport.BeginInvoke(ShowJoinGameButton);
            OnGameStarted += () => ThreadSupport.BeginInvoke(openExtensionsMenuButton.Lock);

            joinGameButton.OnClick += InvokeOnGameJoined;
            OnGameJoined += () => ThreadSupport.BeginInvoke(StartNewGame);

            #region Extensions Menu
            openExtensionsMenuButton.AddHideAndShowEvent(extensionsMenuPage);
            OnMenuRevert += ExtensionsMenuAPI.InvokeOnMenuReverted;
            OnConnected += ExtensionsMenuAPI.InvokeOnConnected;
            OnDisconnected += ExtensionsMenuAPI.InvokeOnDisconnected;
            OnDisconnected += () => ClientConnection.ClearMenuListener(this);
            OnReady += metadata =>
            {
                ExtensionsMenuAPI.InvokeOnAddReadyMetadata(metadata);
                ExtensionsMenuAPI.InvokeOnReady();
            };
            OnUnready += ExtensionsMenuAPI.InvokeOnUnready;
            OnRoomStateUpdated += ExtensionsMenuAPI.InvokeRoomStateUpdated;
            OnLockSettings += ExtensionsMenuAPI.InvokeOnLockSettings;
            OnGameStarted += ExtensionsMenuAPI.InvokeOnGameStarted;
            OnGameJoined += ExtensionsMenuAPI.InvokeOnGameJoined;
            #endregion

            menuPage.backButton.OnClick += () => ThreadSupport.BeginInvoke(RevertToInitialState);
        }
        //定制 - 使用随机Mod的汉化功能
        internal static string LocalizeRando(string text) {
            return Localization.Localize(text);
        }

        //定制 - 控制显示页面
        private void HideAll()
        {
            //身份
            hostButton.Hide();
            searchButton.Hide();
            //设置
            additionalSettingsLabel.Hide();
            syncSimpleKeysUsagesButton.Hide();
            syncVanillaItemsButton.Hide();
            openExtensionsMenuButton.Hide();
            localPHollowKnightRefsLabel.Hide();
            //大厅
            serverNameLabel.Hide();
            nicknameInput.Hide();
            roomInput.Hide();
            readyButton.Hide();
            searchButton.Hide();
            startButton.Hide();
            readyPlayersBox.Hide();
            readyPlayersCounter.Hide();
            //搜索
            searchRoomHint.Hide();
            roomsPanel.Hide();
            //连接
            urlInput.Hide();
            connectButton.Hide();
        }
        private void ShowIdentityChoice()
        {
            HideAll();
            hostButton.Show();
            searchButton.Show();
        }
        private void ShowLobby()
        {
            HideAll();
            serverNameLabel.Show();
            nicknameInput.Show();
            roomInput.Show();
            readyButton.Show();
            nicknameInput.InputField.Select();
            if (ItemSyncMod.GS.IsHost)
            {
                ShowSettings(true);
                roomInput.Unlock();
            }
            else
            {
                Modding.Logger.Log("锁住roomButton");
                roomInput.Lock();
            }

        }

        private void ShowSettings(bool bShow)
        {
            if (bShow)
            {
                additionalSettingsLabel.Show();
                syncVanillaItemsButton.Show();
                syncSimpleKeysUsagesButton.Show();
                openExtensionsMenuButton.Show();
                localPHollowKnightRefsLabel.Show();
            }
            else
            {
                additionalSettingsLabel.Hide();
                syncVanillaItemsButton.Hide();
                syncSimpleKeysUsagesButton.Hide();
                openExtensionsMenuButton.Hide();
                localPHollowKnightRefsLabel.Hide();
            }

        }
        public void ShowHint(string inHint)
        {
            HideAll();
            searchRoomHint.Show();
            searchRoomHint.Text.text = LocalizeRando(inHint);
        }
        internal void ShowSearchResult(List<(string, string)> results)
        {

            HideAll();
            if (results.Count == 0)
            {
                ShowHint(LocalizeRando("No Room Found"));
            }
            else
            {
                roomsPanel.Destroy();
                foreach ((string, string) item in results)
                {
                    RoomButton roomButton = new(menuPage, item.Item1, item.Item2);
                    roomsPanel.Add(roomButton);
                    roomButton.OnClick += () => roomButtonClicked(roomButton);
                }
                searchRoomHint.Hide();
                roomsPanel.Show();
            }
        }

        //定制 - 加入搜索功能
        private void SendSearchRoom()
        {
            ItemSyncMod.Connection.SearchRoom();
        }
        private void HostClicked()
        {
            try
            {
                ItemSyncMod.GS.IsHost = true;
                ShowHint(LocalizeRando("Connecting"));
                Modding.Logger.Log($"Connection:{ItemSyncMod.Connection != null}");
                AutoConnect();
            }
            catch (Exception ex)
            {
                Modding.Logger.Log($"Connection:{ItemSyncMod.Connection != null}");
                ShowHint(LocalizeRando(ex.Message));
            }
        }

        private void SearchClicked()
        {
            try
            {
                ItemSyncMod.GS.IsHost = false;
                ShowHint(LocalizeRando("Connecting"));
                AutoConnect();
            }
            catch (Exception ex)
            {
                ShowHint(LocalizeRando(ex.Message));
            }
        }
        private void roomButtonClicked(RoomButton roomButton)
        {
            ShowHint(LocalizeRando("Joining Room"));
            try
            {
                SettingsMenu menu = SettingsMenu.instance;
                if(menu == null)
                {
                    throw new Exception("SettingsMenu无效");
                }
                Modding.Logger.Log($"加载配置代码:{roomButton.code}");
                menu.OpenLoadKey(roomButton.code);
                ThreadSupport.BeginInvoke(RandomizerMenu.instance.OpenRandomize);
                //在随机完成后再进入房间
                RandomizerMenu.instance.OnRandomizeSuccess += () =>
                {
                    Modding.Logger.Log("随机完成进入房间");
                    roomInput.SetValue(roomButton.room);
                    ShowLobby();
                };
            }
            catch (Exception ex)
            {
                ShowHint(LocalizeRando(ex.Message));
            }
        }
        //定制 - 连接multiworld
        private void AutoConnect()
        {
            if (connectThread is not null && connectThread.IsAlive) connectThread.Abort();
            connectThread = new Thread(MyConnect);

            ClientConnection.SetMenuListener(this);
            connectThread.Start();
        }
        // 定制 - 硬编码ip端口
        private void MyConnect()
        {
            ItemSyncMod.Connection.Connect(ItemSyncMod.GS.URL);
        }

        private void InvokeOnRoomStateUpdated(int count, string[] names) => OnRoomStateUpdated.Invoke(count, names);
        private void InvokeOnGameStarted() => OnGameStarted?.Invoke();
        private void InvokeOnGameJoined() => OnGameJoined?.Invoke();

        private void Arrange()
        {
            //定制 模式选择
            hostButton.MoveTo(new(0, 50));
            searchButton.MoveTo(new(0, -50));
            hostButton.SetNeighbor(Neighbor.Right, searchButton);

            //定制 - 大厅
            searchRoomHint.MoveTo(new(0, 0));

            urlInput.MoveTo(new(0, 300));
            serverNameLabel.MoveTo(urlInput.Label.GameObject.transform.localPosition);
            connectButton.MoveTo(new(0, 250));

            nicknameInput.MoveTo(new(0, 140));
            roomInput.MoveTo(new(0, 0));
            readyPlayersBox.MoveTo(new(600, 430));
            readyPlayersCounter.MoveTo(new(600, 470));
            readyButton.MoveTo(new(0, -100));
            startButton.MoveTo(new(0, -200));
            joinGameButton.MoveTo(new(0,-200));

            additionalSettingsLabel.MoveTo(new(-600, 470));
            syncVanillaItemsButton.MoveTo(new(-600, 400));
            syncSimpleKeysUsagesButton.MoveTo(new(-600, 350));
            openExtensionsMenuButton.MoveTo(new(-600, 280));

            localPHollowKnightRefsLabel.MoveTo(new(-600, -300));
            
            urlInput.SymSetNeighbor(Neighbor.Down, connectButton);
            nicknameInput.SymSetNeighbor(Neighbor.Down, roomInput);
            roomInput.SymSetNeighbor(Neighbor.Down, readyButton);
            readyButton.SymSetNeighbor(Neighbor.Down, startButton);
            
            syncVanillaItemsButton.SymSetNeighbor(Neighbor.Down, syncSimpleKeysUsagesButton);
            
            syncVanillaItemsButton.SymSetNeighbor(Neighbor.Right, readyButton);
            syncSimpleKeysUsagesButton.SetNeighbor(Neighbor.Right, readyButton);
        }

        private void RevertToInitialState()
        {
            // 定制 - 初始界面
            // Set menu objects (in)active

            ShowIdentityChoice();

            connectButton.SetText(LocalizeRando("Connect"));
            connectButton.SetValue(false);

            readyButton.Unlock();
            readyButton.SetText(LocalizeRando("Ready"));
            readyButton.SetValue(false);

            readyPlayersBox.SetText("");
            readyPlayersCounter.Set(0);

            UnlockSettingsButton();

            ItemSyncMod.Connection.Disconnect();
            OnDisconnected.Invoke();        // 添加：清空menulistener
            try
            {
                OnMenuRevert?.Invoke();
            }
            catch (Exception e)
            {
                LogHelper.LogError($"OnMenuRevert error: {e.Message}");
                LogHelper.LogError(e.StackTrace);
            }
        }

        internal bool GetMenuButton(out BaseButton button)
        {
            button = openMenuButton;
            return true;
        }

        private void UpdateNickname(string newNickname)
        {
            ItemSyncMod.GS.UserName = newNickname;
        }

        private void ConnectClicked()
        {
            bool newValue = connectButton.Value;
            if (newValue)
            {
                if (connectThread is not null && connectThread.IsAlive) connectThread.Abort();
                connectButton.SetText("Connecting");
                connectThread = new Thread(Connect);

                ClientConnection.SetMenuListener(this);
                connectThread.Start();
            }
            else
            {
                RevertToInitialState();
                OnDisconnected?.Invoke();
            }
        }

        private void Connect()
        {
            try
            {
                //定制 - 硬编码ip
                string url = ItemSyncMod.GS.URL;
                ItemSyncMod.Connection.Connect(url);
                ItemSyncMod.GS.URL = url;
            }
            catch
            {
                LogHelper.Log("Failed to connect!");
                connectButton.SetValue(false);
                return;
            }

        }

        private void ConnectAcknowledged(ulong uid, string serverName)
        {
            ThreadSupport.BeginInvoke(() =>
            {
                //定制 - 身份决定连接完成后的菜单
                if (ItemSyncMod.GS.IsHost)
                {
                    connectButton.SetText(LocalizeRando("Disconnect"));
                    serverNameLabel.Text.text = LocalizeRando("Server Name: ") + $"{serverName}";
                    nicknameInput.Unlock();
                    roomInput.Unlock();
                    OnConnected?.Invoke();
                    ShowLobby();
                }
                else
                {
                    ShowHint(LocalizeRando("Searching Room"));
                    SendSearchRoom();
                }
            });
        }

        private void ReadyClicked()
        {
            if (readyButton.Value)
            {
                nicknameInput.Lock();
                roomInput.Lock();
                Dictionary<string, string> metadataDict = new();
                OnReady?.Invoke(metadataDict);
                ItemSyncMod.Connection.ReadyUp(roomInput.Value, ItemSyncMod.Controller.GetHash(), metadataDict.Select(e => (e.Key, e.Value)).ToArray());
                readyPlayersBox.Show();
                readyPlayersCounter.Show();
            }
            else
            {
                if (ItemSyncMod.Connection.IsConnected()) ItemSyncMod.Connection.Unready();
                startButton.Hide();

                readyButton.SetText(LocalizeRando("Ready"));
                readyPlayersBox.SetText("");
                readyPlayersBox.Hide();
                readyPlayersCounter.Set(0);
                readyPlayersCounter.Hide();

                // 定制 - 对房间人员永远锁住房间名.
                nicknameInput.Unlock();
                if (ItemSyncMod.GS.IsHost)
                {
                    roomInput.Unlock();
                }

                UnlockSettingsButton();
                OnUnready?.Invoke();
            }
        }

        private void UpdateReadyPlayersLabel(int num, string[] playersNames)
        {
            readyPlayersCounter.Set(num);
            readyPlayersBox.SetText(playersNames);
        }

        private void EnsureStartButtonShown()
        {
            if (startButton.Hidden)
            {
                //定制 - 身份区别大厅
                if (ItemSyncMod.GS.IsHost)
                {
                    startButton.Show();
                }
                else
                {
                    startButton.Hide();
                }
                readyButton.SetText(LocalizeRando("Unready"));
            }
        }

        private void ShowReadyDeny(string description)
        {
            readyButton.SetText(LocalizeRando("Ready"));
            readyButton.SetValue(false);
            readyPlayersBox.SetText(description);
            nicknameInput.Unlock();
            roomInput.Unlock();

            roomInput.InputField.Select();
            OnUnready?.Invoke();
        }

        private void InitiateGame()
        {
            readyButton.Lock();
            startButton.Hide();

            LockSettingsButtons();
            ItemSyncMod.Connection.InitiateGame(SettingsSharer.GetSerializedSettings());
        }

        internal string GetSyncSimpleKeysUsages() => syncSimpleKeysUsagesButton.Value.ToString();

        internal void SetSyncSimpleKeysUsages(string literalValue)
        {
            ThreadSupport.BeginInvoke(() =>
            {
                if (!syncSimpleKeysUsagesButton.Locked)
                    syncSimpleKeysUsagesButton.SetValue(bool.Parse(literalValue));
            });
        }

        internal string GetSyncVanillaItems() => syncVanillaItemsButton.Value.ToString();

        internal void SetSyncVanillaItems(string literalValue)
        {
            ThreadSupport.BeginInvoke(() =>
            {
                if (!syncVanillaItemsButton.Locked)
                    syncVanillaItemsButton.SetValue(bool.Parse(literalValue));
            });
        }

        internal void LockSettingsButtons()
        {
            ThreadSupport.BeginInvoke(() => {
                syncVanillaItemsButton.Lock();
                syncSimpleKeysUsagesButton.Lock();
                openExtensionsMenuButton.Lock();
            });

            OnLockSettings?.Invoke();
        }

        internal void UnlockSettingsButton()
        {
            ThreadSupport.BeginInvoke(() =>
            {
                syncVanillaItemsButton.Unlock();
                syncSimpleKeysUsagesButton.Unlock();
                openExtensionsMenuButton.Unlock();
            });
        }

        // Workaround for unity main thread crashes
        private void StartNewGame() => ItemSyncMod.Controller.StartGame();

        internal void ShowJoinGameButton()
        {
            connectButton.Hide();
            readyButton.Hide();
            startButton.Hide();
            joinGameButton.Show();
        }
    }
}
